package ipamdriver

import (
	"errors"
	// "net"
	log "github.com/sirupsen/logrus"
	ipamApi "github.com/docker/go-plugins-helpers/ipam"
)

const localAddressSpace = "LOCAL"
const globalAddressSpace = "GLOBAL"

const (
	Current = "1"
	Flat    = "flat"
)

type QingluanIpam struct {
	Name  string
	allocatedIPAddresses map[string]struct{}
}

func (driver *QingluanIpam) GetCapabilities() (*ipamApi.CapabilitiesResponse, error) {
	log.Debugf("GetCapabilities called")
	return &ipamApi.CapabilitiesResponse{RequiresMACAddress: true}, nil
}

func (driver *QingluanIpam) GetDefaultAddressSpaces() (*ipamApi.AddressSpacesResponse, error) {
	log.Debugf("GetDefaultAddressSpaces called")
	log.Debugf("Returing response LocalDefaultAddressSpace: %s, GlobalDefaultAddressSpace: %s",
		localAddressSpace, globalAddressSpace)

	return &ipamApi.AddressSpacesResponse{LocalDefaultAddressSpace: localAddressSpace,
		GlobalDefaultAddressSpace: globalAddressSpace}, nil
}

func (driver *QingluanIpam) RequestPool(request *ipamApi.RequestPoolRequest) (*ipamApi.RequestPoolResponse, error) {
	log.Debugf("RequestPool called")
	var (
		network string
		gateway string
		model   string
		poolID  string
		vni     string
	)
	poolID = Uuid()
	// get network pool type
	if len(request.Options) == 0 {
		return &ipamApi.RequestPoolResponse{}, errors.New("Input pool type, eg:nonat,nat...")
	}else {
		model = request.Options["pool"]
	}
	// get network pool value
	// 1.from custom type --subnet
	// 2.from etcd
	if request.Pool != "" {
		network = request.Pool
		gateway = getGatewayIP(network)
		if model == "vlan" || model == "vxlan" {
			vni = request.Options["vni"]
		}
		if model == Flat{
			if err := SetFlatNet(poolID, network, model); err != nil {
				return &ipamApi.RequestPoolResponse{},  errors.New("Set network info error.")
			}
		}else{
			if err := SetNetworkInfo(network, gateway, string(poolID), model, vni, Current); err != nil {
				return &ipamApi.RequestPoolResponse{}, errors.New("Set network info error.")
			}
		}
	}else {
		if model == Flat{
			network = request.Pool
			if network == "" {
				return &ipamApi.RequestPoolResponse{},  errors.New("input subnet value, eg:192.168.159.0/24 ")
			}
			// gateway = request.Gateway
			// network = SetFlatInfo(poolID, network, gateway)
		}else{
			vni = request.Options["vni"]
			network, _ = GetNextNetPool(model, poolID, vni, Current)
		}
	}
	return &ipamApi.RequestPoolResponse{
		PoolID: poolID, 
		Pool:  network,
	}, nil
}

func (driver *QingluanIpam) ReleasePool(request *ipamApi.ReleasePoolRequest) error {
	log.Debugf("ReleasePool called")
	if res, _ := CurrentIsOne(request.PoolID); res == false {
		errors.New("response from daemon: network has active endpoints")
	}

	networkType := getNetAttr(request.PoolID, "Type")
	network := getNetAttr(request.PoolID, "Network")
	if networkType == Flat {
		if err := deleteNetwork(request.PoolID); err != nil{
			return err
		}
	}else{
		if networkInPool(request.PoolID, networkType) {
			if err := deleteNetwork(request.PoolID); err != nil{
				return err
			}
			updateRecovery(networkType, network)
		}else{
			if err := deleteNetwork(request.PoolID); err != nil{
				return err
			}
		}
	}
	return nil
}

func (driver *QingluanIpam) RequestAddress(request *ipamApi.RequestAddressRequest) (*ipamApi.RequestAddressResponse, error) {
	log.Debugf("RequestAddress called")
	model := getNetAttr(request.PoolID, "Type")
	// custom parameter gateway or address
	// flat model don't do anything
	// other model update Current value
	if request.Address != ""{
		if model != Flat{
			if err := updateCurrent(request.PoolID); err != nil {
				return &ipamApi.RequestAddressResponse{}, nil
			}
		}
		return &ipamApi.RequestAddressResponse{Address: request.Address +"/"+ getNetAttr(request.PoolID, "Prefix")}, nil
	}else{
		if model != Flat{
			addr, _ := GetNextAddress(request.PoolID)
			return &ipamApi.RequestAddressResponse{Address: addr}, nil
		}else{
			return &ipamApi.RequestAddressResponse{}, errors.New("Flat network model, please input gateway.")
		}
	}	
	
}

func (driver *QingluanIpam) ReleaseAddress(request *ipamApi.ReleaseAddressRequest) error {
	log.Debugf("ReleaseAddress called")
	poolId, address := request.PoolID, request.Address
	log.Debugf("IP:%s",address)
	if err := releaseAddress(poolId, address); err != nil {
		return err
	}
	return nil
}

func NewQingluanIpam() *QingluanIpam{
	log.Debugf("startup qingluan Ipam plugin")
	driver  := QingluanIpam{
		allocatedIPAddresses: make(map[string]struct{}),
		Name: "qingluanIpam",
	}
	return &driver
}
